package com.huffman.smart_picture.service.impl;

import cn.hutool.json.JSONUtil;
import com.huffman.smart_picture.domain.constants.RedisConstant;
import com.huffman.smart_picture.domain.vo.manage.DashboardDataCountVo;
import com.huffman.smart_picture.domain.vo.manage.DashboardSpaceRatioVo;
import com.huffman.smart_picture.domain.vo.manage.DashboardUserRatioVo;
import com.huffman.smart_picture.service.ManageService;
import com.huffman.smart_picture.service.PictureService;
import com.huffman.smart_picture.service.SpaceService;
import com.huffman.smart_picture.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * @author yrforest
 * @version 1.0
 * @description: TODO
 * @date 2025/7/17 18:04
 */
@Service
@RequiredArgsConstructor
public class ManageServiceImpl implements ManageService {

    private final UserService userService;
    private final PictureService pictureService;
    private final SpaceService spaceService;
    private final StringRedisTemplate redisTemplate;

    @Override
    public DashboardDataCountVo getDashboardDataCount() {
        // 先查redis
        String dashboardCountStr = redisTemplate.opsForValue().get(RedisConstant.DASHBOARD_COUNT_KEY);
        DashboardDataCountVo dashboardDataCountVo = null;
        if (dashboardCountStr != null) {
            dashboardDataCountVo = JSONUtil.toBean(dashboardCountStr, DashboardDataCountVo.class);
            return dashboardDataCountVo;
        }
        // redis 未命中查数据库
        CompletableFuture<Long> userCountFuture = CompletableFuture.supplyAsync(
                () -> userService.lambdaQuery().count());
        CompletableFuture<Long> pictureCountFuture = CompletableFuture.supplyAsync(
                () -> pictureService.lambdaQuery().count());
        CompletableFuture<Long> spaceCountFuture = CompletableFuture.supplyAsync(
                () -> spaceService.lambdaQuery().count());

        // 等待所有任务完成
        CompletableFuture.allOf(userCountFuture, pictureCountFuture, spaceCountFuture).join();
        Long userCount = Optional.ofNullable(userCountFuture.join()).orElse(0L);
        Long pictureCount = Optional.ofNullable(pictureCountFuture.join()).orElse(0L);
        Long spaceCount = Optional.ofNullable(spaceCountFuture.join()).orElse(0L);
        dashboardDataCountVo = new DashboardDataCountVo();
        dashboardDataCountVo.setUserCount(userCount);
        dashboardDataCountVo.setImageCount(pictureCount);
        dashboardDataCountVo.setSpaceCount(spaceCount);

        // 写入redis
        redisTemplate.opsForValue().set(RedisConstant.DASHBOARD_COUNT_KEY, JSONUtil.toJsonStr(dashboardDataCountVo), 1, TimeUnit.HOURS);

        return dashboardDataCountVo;
    }

    @Override
    public DashboardUserRatioVo getDashboardUserRatio() {
//        String cacheStr = redisTemplate.opsForValue().get(RedisConstant.DASHBOARD_USER_RATIO_KEY);
//        DashboardUserRatioVo dashboardUserRatioVo = null;
//        if (cacheStr != null) {
//            dashboardUserRatioVo = JSONUtil.toBean(cacheStr, DashboardUserRatioVo.class);
//            return dashboardUserRatioVo;
//        }
//        dashboardUserRatioVo = userService.vipAndNonVipCount();
//        // 写入redis
//        redisTemplate.opsForValue().set(RedisConstant.DASHBOARD_USER_RATIO_KEY, JSONUtil.toJsonStr(dashboardUserRatioVo), 1, TimeUnit.HOURS);
        DashboardUserRatioVo dashboardUserRatioVo = getRedisInfo(RedisConstant.DASHBOARD_USER_RATIO_KEY, DashboardUserRatioVo.class, () -> userService.vipAndNonVipCount());
        return dashboardUserRatioVo;
    }

    @Override
    public DashboardSpaceRatioVo getDashboardSpaceRatio() {
        return getRedisInfo(RedisConstant.DASHBOARD_SPACE_RATIO_KEY, DashboardSpaceRatioVo.class, spaceService::getSpaceLevelRatio);
    }

    /**
     * 从redis或数据库中获取数据通用方法
     *
     * @param redisKey
     * @param clazz
     * @param supplier
     * @param <T>
     * @return
     */
    private <T> T getRedisInfo(String redisKey, Class<T> clazz, Supplier<T> supplier) {
        String cacheStr = redisTemplate.opsForValue().get(redisKey);
        T t = null;
        if (cacheStr != null) {
            t = JSONUtil.toBean(cacheStr, clazz);
            return t;
        }

        t = supplier.get();
        // 写入redis
        redisTemplate.opsForValue().set(redisKey, JSONUtil.toJsonStr(t), 1, TimeUnit.HOURS);
        return t;
    }
}
